<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<meta name="theme-color" content="#222"><meta name="generator" content="Hexo 5.4.2">

  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">



<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" integrity="sha256-HtsXJanqjKTc8vVQjO4YMhiqFoXkfBsjBWcX91T1jr8=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.1.1/animate.min.css" integrity="sha256-PR7ttpcvz8qrF57fur/yAx1qXMFJeJFiA6pSzWi0OIE=" crossorigin="anonymous">

<script class="next-config" data-name="main" type="application/json">{"hostname":"xiaoqingming18.github.io","root":"/","images":"/images","scheme":"Muse","darkmode":false,"version":"8.15.1","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12},"copycode":{"enable":false,"style":null},"bookmark":{"enable":false,"color":"#222","save":"auto"},"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"stickytabs":false,"motion":{"enable":true,"async":false,"transition":{"menu_item":"fadeInDown","post_block":"fadeIn","post_header":"fadeInDown","post_body":"fadeInDown","coll_header":"fadeInLeft","sidebar":"fadeInUp"}},"prism":false,"i18n":{"placeholder":"搜索...","empty":"没有找到任何搜索结果：${query}","hits_time":"找到 ${hits} 个搜索结果（用时 ${time} 毫秒）","hits":"找到 ${hits} 个搜索结果"}}</script><script src="/js/config.js"></script>

    <meta name="description" content="一、浏览器生成消息1.1 生成HTTP请求消息1.1.1 什么是URL我们的网络体验从在浏览器中输入网址开始。网址，即URL，URL通过开头不同的标识区分不同的服务，例如访问Web服务器时使用”http:&#x2F;&#x2F;&quot;，访问FTP服务器时使用&quot;ftp:&#x2F;&#x2F;&quot;。 下图列举了几种常用的互联网URL：  URL的写法不同，但它们有一个共同点，就是URL开头的文字，即“http:”“ftp:”“file:”“ma">
<meta property="og:type" content="article">
<meta property="og:title" content="计算机网络：网络是怎样连接的">
<meta property="og:url" content="http://xiaoqingming18.github.io/2023/07/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%EF%BC%9A%E7%BD%91%E7%BB%9C%E6%98%AF%E6%80%8E%E6%A0%B7%E8%BF%9E%E6%8E%A5%E7%9A%84/index.html">
<meta property="og:site_name" content="鸣蜩十七">
<meta property="og:description" content="一、浏览器生成消息1.1 生成HTTP请求消息1.1.1 什么是URL我们的网络体验从在浏览器中输入网址开始。网址，即URL，URL通过开头不同的标识区分不同的服务，例如访问Web服务器时使用”http:&#x2F;&#x2F;&quot;，访问FTP服务器时使用&quot;ftp:&#x2F;&#x2F;&quot;。 下图列举了几种常用的互联网URL：  URL的写法不同，但它们有一个共同点，就是URL开头的文字，即“http:”“ftp:”“file:”“ma">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="http://xiaoqingming18.github.io/2023/07/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%EF%BC%9A%E7%BD%91%E7%BB%9C%E6%98%AF%E6%80%8E%E6%A0%B7%E8%BF%9E%E6%8E%A5%E7%9A%84/常见的URL.png">
<meta property="og:image" content="http://xiaoqingming18.github.io/2023/07/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%EF%BC%9A%E7%BD%91%E7%BB%9C%E6%98%AF%E6%80%8E%E6%A0%B7%E8%BF%9E%E6%8E%A5%E7%9A%84/HTTP协议.png">
<meta property="og:image" content="http://xiaoqingming18.github.io/2023/07/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%EF%BC%9A%E7%BD%91%E7%BB%9C%E6%98%AF%E6%80%8E%E6%A0%B7%E8%BF%9E%E6%8E%A5%E7%9A%84/HTTP的主要方法.png">
<meta property="og:image" content="http://xiaoqingming18.github.io/2023/07/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%EF%BC%9A%E7%BD%91%E7%BB%9C%E6%98%AF%E6%80%8E%E6%A0%B7%E8%BF%9E%E6%8E%A5%E7%9A%84/HTTP消息的格式.png">
<meta property="og:image" content="http://xiaoqingming18.github.io/2023/07/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%EF%BC%9A%E7%BD%91%E7%BB%9C%E6%98%AF%E6%80%8E%E6%A0%B7%E8%BF%9E%E6%8E%A5%E7%9A%84/HTTP状态码概要.png">
<meta property="og:image" content="http://xiaoqingming18.github.io/2023/07/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%EF%BC%9A%E7%BD%91%E7%BB%9C%E6%98%AF%E6%80%8E%E6%A0%B7%E8%BF%9E%E6%8E%A5%E7%9A%84/IP的基本思路.png">
<meta property="og:image" content="http://xiaoqingming18.github.io/2023/07/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%EF%BC%9A%E7%BD%91%E7%BB%9C%E6%98%AF%E6%80%8E%E6%A0%B7%E8%BF%9E%E6%8E%A5%E7%9A%84/IP地址的结构.png">
<meta property="og:image" content="http://xiaoqingming18.github.io/2023/07/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%EF%BC%9A%E7%BD%91%E7%BB%9C%E6%98%AF%E6%80%8E%E6%A0%B7%E8%BF%9E%E6%8E%A5%E7%9A%84/子网掩码第一种写法.png">
<meta property="og:image" content="http://xiaoqingming18.github.io/2023/07/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%EF%BC%9A%E7%BD%91%E7%BB%9C%E6%98%AF%E6%80%8E%E6%A0%B7%E8%BF%9E%E6%8E%A5%E7%9A%84/子网掩码简写法.png">
<meta property="og:image" content="http://xiaoqingming18.github.io/2023/07/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%EF%BC%9A%E7%BD%91%E7%BB%9C%E6%98%AF%E6%80%8E%E6%A0%B7%E8%BF%9E%E6%8E%A5%E7%9A%84/主机号特殊点.png">
<meta property="og:image" content="http://xiaoqingming18.github.io/2023/07/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%EF%BC%9A%E7%BD%91%E7%BB%9C%E6%98%AF%E6%80%8E%E6%A0%B7%E8%BF%9E%E6%8E%A5%E7%9A%84/DNS服务器的基本工作.png">
<meta property="og:image" content="http://xiaoqingming18.github.io/2023/07/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%EF%BC%9A%E7%BD%91%E7%BB%9C%E6%98%AF%E6%80%8E%E6%A0%B7%E8%BF%9E%E6%8E%A5%E7%9A%84/寻找DNS服务器过程.png">
<meta property="og:image" content="http://xiaoqingming18.github.io/2023/07/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%EF%BC%9A%E7%BD%91%E7%BB%9C%E6%98%AF%E6%80%8E%E6%A0%B7%E8%BF%9E%E6%8E%A5%E7%9A%84/数据收发过程.png">
<meta property="og:image" content="http://xiaoqingming18.github.io/2023/07/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%EF%BC%9A%E7%BD%91%E7%BB%9C%E6%98%AF%E6%80%8E%E6%A0%B7%E8%BF%9E%E6%8E%A5%E7%9A%84/描述符与端口号的区别.png">
<meta property="og:image" content="http://xiaoqingming18.github.io/2023/07/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%EF%BC%9A%E7%BD%91%E7%BB%9C%E6%98%AF%E6%80%8E%E6%A0%B7%E8%BF%9E%E6%8E%A5%E7%9A%84/协议栈的结构.png">
<meta property="og:image" content="http://xiaoqingming18.github.io/2023/07/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%EF%BC%9A%E7%BD%91%E7%BB%9C%E6%98%AF%E6%80%8E%E6%A0%B7%E8%BF%9E%E6%8E%A5%E7%9A%84/TCP头部格式.png">
<meta property="og:image" content="http://xiaoqingming18.github.io/2023/07/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%EF%BC%9A%E7%BD%91%E7%BB%9C%E6%98%AF%E6%80%8E%E6%A0%B7%E8%BF%9E%E6%8E%A5%E7%9A%84/客户端与服务器之间交换的控制信息.png">
<meta property="og:image" content="http://xiaoqingming18.github.io/2023/07/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%EF%BC%9A%E7%BD%91%E7%BB%9C%E6%98%AF%E6%80%8E%E6%A0%B7%E8%BF%9E%E6%8E%A5%E7%9A%84/控制信息分类.png">
<meta property="article:published_time" content="2023-07-12T01:07:23.000Z">
<meta property="article:modified_time" content="2023-07-24T07:13:28.491Z">
<meta property="article:author" content="鸣蜩十七">
<meta property="article:tag" content="-网络是怎样连接的 -读书笔记">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="http://xiaoqingming18.github.io/2023/07/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%EF%BC%9A%E7%BD%91%E7%BB%9C%E6%98%AF%E6%80%8E%E6%A0%B7%E8%BF%9E%E6%8E%A5%E7%9A%84/常见的URL.png">


<link rel="canonical" href="http://xiaoqingming18.github.io/2023/07/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%EF%BC%9A%E7%BD%91%E7%BB%9C%E6%98%AF%E6%80%8E%E6%A0%B7%E8%BF%9E%E6%8E%A5%E7%9A%84/">



<script class="next-config" data-name="page" type="application/json">{"sidebar":"","isHome":false,"isPost":true,"lang":"zh-CN","comments":true,"permalink":"http://xiaoqingming18.github.io/2023/07/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%EF%BC%9A%E7%BD%91%E7%BB%9C%E6%98%AF%E6%80%8E%E6%A0%B7%E8%BF%9E%E6%8E%A5%E7%9A%84/","path":"2023/07/12/计算机网络：网络是怎样连接的/","title":"计算机网络：网络是怎样连接的"}</script>

<script class="next-config" data-name="calendar" type="application/json">""</script>
<title>计算机网络：网络是怎样连接的 | 鸣蜩十七</title>
  








  <noscript>
    <link rel="stylesheet" href="/css/noscript.css">
  </noscript>

<style>.github-emoji { position: relative; display: inline-block; width: 1.2em; min-height: 1.2em; overflow: hidden; vertical-align: top; color: transparent; }  .github-emoji > span { position: relative; z-index: 10; }  .github-emoji img, .github-emoji .fancybox { margin: 0 !important; padding: 0 !important; border: none !important; outline: none !important; text-decoration: none !important; user-select: none !important; cursor: auto !important; }  .github-emoji img { height: 1.2em !important; width: 1.2em !important; position: absolute !important; left: 50% !important; top: 50% !important; transform: translate(-50%, -50%) !important; user-select: none !important; cursor: auto !important; } .github-emoji-fallback { color: inherit; } .github-emoji-fallback img { opacity: 0 !important; }</style>
</head>

<body itemscope itemtype="http://schema.org/WebPage" class="use-motion">
  <div class="headband"></div>

  <main class="main">
    <div class="column">
      <header class="header" itemscope itemtype="http://schema.org/WPHeader"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏" role="button">
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <i class="logo-line"></i>
      <p class="site-title">鸣蜩十七</p>
      <i class="logo-line"></i>
    </a>
      <p class="site-subtitle" itemprop="description">鸣蜩十七是和女朋友谈恋爱的日子</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger" aria-label="搜索" role="button">
    </div>
  </div>
</div>



<nav class="site-nav">
  <ul class="main-menu menu"><li class="menu-item menu-item-home"><a href="/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a></li><li class="menu-item menu-item-about"><a href="/about/" rel="section"><i class="fa fa-user fa-fw"></i>关于</a></li><li class="menu-item menu-item-tags"><a href="/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签</a></li><li class="menu-item menu-item-categories"><a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类</a></li><li class="menu-item menu-item-archives"><a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档</a></li><li class="menu-item menu-item-schedule"><a href="/schedule/" rel="section"><i class="fa fa-calendar fa-fw"></i>日程表</a></li><li class="menu-item menu-item-sitemap"><a href="/sitemap.xml" rel="section"><i class="fa fa-sitemap fa-fw"></i>站点地图</a></li><li class="menu-item menu-item-commonweal"><a href="/404/" rel="section"><i class="fa fa-heartbeat fa-fw"></i>公益 404</a></li>
  </ul>
</nav>




</header>
        
  
  <aside class="sidebar">

    <div class="sidebar-inner sidebar-nav-active sidebar-toc-active">
      <ul class="sidebar-nav">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <div class="sidebar-panel-container">
        <!--noindex-->
        <div class="post-toc-wrap sidebar-panel">
            <div class="post-toc animated"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%B8%80%E3%80%81%E6%B5%8F%E8%A7%88%E5%99%A8%E7%94%9F%E6%88%90%E6%B6%88%E6%81%AF"><span class="nav-text">一、浏览器生成消息</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-1-%E7%94%9F%E6%88%90HTTP%E8%AF%B7%E6%B1%82%E6%B6%88%E6%81%AF"><span class="nav-text">1.1 生成HTTP请求消息</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1-1-1-%E4%BB%80%E4%B9%88%E6%98%AFURL"><span class="nav-text">1.1.1 什么是URL</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-1-2-%E6%B5%8F%E8%A7%88%E5%99%A8%E8%A7%A3%E6%9E%90URL"><span class="nav-text">1.1.2 浏览器解析URL</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-1-3-%E4%BB%80%E4%B9%88%E6%98%AFHTTP%E5%8D%8F%E8%AE%AE"><span class="nav-text">1.1.3 什么是HTTP协议</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-1-4-%E7%94%9F%E6%88%90HTTP%E8%AF%B7%E6%B1%82%E6%B6%88%E6%81%AF"><span class="nav-text">1.1.4 生成HTTP请求消息</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-1-5-%E5%8F%91%E9%80%81%E8%AF%B7%E6%B1%82%E5%90%8E%E6%94%B6%E5%88%B0%E5%93%8D%E5%BA%94"><span class="nav-text">1.1.5 发送请求后收到响应</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#1-2-%E5%90%91DNS%E6%9C%8D%E5%8A%A1%E5%99%A8%E6%9F%A5%E8%AF%A2Web%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%9A%84IP%E5%9C%B0%E5%9D%80"><span class="nav-text">1.2 向DNS服务器查询Web服务器的IP地址</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1-2-1-%E4%BB%80%E4%B9%88%E6%98%AFIP%E5%9C%B0%E5%9D%80"><span class="nav-text">1.2.1 什么是IP地址</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-2-2-Socket%E5%BA%93%E6%8F%90%E4%BE%9B%E6%9F%A5%E8%AF%A2IP%E5%9C%B0%E5%9D%80%E7%9A%84%E5%8A%9F%E8%83%BD"><span class="nav-text">1.2.2 Socket库提供查询IP地址的功能</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-2-3-%E9%80%9A%E8%BF%87%E8%A7%A3%E6%9E%90%E5%99%A8%E5%90%91DNS%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%8F%91%E5%87%BA%E6%9F%A5%E8%AF%A2"><span class="nav-text">1.2.3 通过解析器向DNS服务器发出查询</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-2-4-%E8%A7%A3%E6%9E%90%E5%99%A8%E7%9A%84%E5%8E%9F%E7%90%86"><span class="nav-text">1.2.4 解析器的原理</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#1-3-%E5%85%A8%E4%B8%96%E7%95%8CDNS%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%9A%84%E5%A4%A7%E6%8E%A5%E5%8A%9B"><span class="nav-text">1.3 全世界DNS服务器的大接力</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1-3-1-DNS%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%9A%84%E5%9F%BA%E6%9C%AC%E5%B7%A5%E4%BD%9C"><span class="nav-text">1.3.1 DNS服务器的基本工作</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-3-2-%E5%9F%9F%E5%90%8D%E7%9A%84%E5%B1%82%E6%AC%A1%E7%BB%93%E6%9E%84"><span class="nav-text">1.3.2 域名的层次结构</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-3-3-%E5%AF%BB%E6%89%BE%E7%9B%B8%E5%BA%94%E7%9A%84DNS%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%B9%B6%E8%8E%B7%E5%8F%96IP%E5%9C%B0%E5%9D%80"><span class="nav-text">1.3.3 寻找相应的DNS服务器并获取IP地址</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-3-4-%E9%80%9A%E8%BF%87%E7%BC%93%E5%AD%98%E5%8A%A0%E5%BF%ABDNS%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%9A%84%E5%93%8D%E5%BA%94"><span class="nav-text">1.3.4 通过缓存加快DNS服务器的响应</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#1-4-%E5%A7%94%E6%89%98%E5%8D%8F%E8%AE%AE%E6%A0%88%E5%8F%91%E9%80%81%E6%B6%88%E6%81%AF"><span class="nav-text">1.4 委托协议栈发送消息</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1-4-1-%E6%95%B0%E6%8D%AE%E6%94%B6%E5%8F%91%E6%93%8D%E4%BD%9C%E6%A6%82%E8%A7%88"><span class="nav-text">1.4.1 数据收发操作概览</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-4-2-%E5%88%9B%E5%BB%BA%E5%A5%97%E6%8E%A5%E5%AD%97%E9%98%B6%E6%AE%B5"><span class="nav-text">1.4.2 创建套接字阶段</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-4-3-%E8%BF%9E%E6%8E%A5%E9%98%B6%E6%AE%B5"><span class="nav-text">1.4.3 连接阶段</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-4-4-%E9%80%9A%E4%BF%A1%E9%98%B6%E6%AE%B5%EF%BC%9A%E4%BC%A0%E9%80%92%E6%B6%88%E6%81%AF"><span class="nav-text">1.4.4 通信阶段：传递消息</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-4-5-%E6%96%AD%E5%BC%80%E9%98%B6%E6%AE%B5%EF%BC%9A%E6%94%B6%E5%8F%91%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9D%9F"><span class="nav-text">1.4.5 断开阶段：收发数据结束</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%AC%AC%E4%B8%80%E7%AB%A0%E7%BB%93%E8%AF%AD"><span class="nav-text">第一章结语</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%BA%8C%E3%80%81%E5%8D%8F%E8%AE%AE%E6%A0%88%E5%92%8C%E7%BD%91%E5%8D%A1"><span class="nav-text">二、协议栈和网卡</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#2-1-%E5%88%9B%E5%BB%BA%E5%A5%97%E6%8E%A5%E5%AD%97"><span class="nav-text">2.1 创建套接字</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#2-1-1-%E5%8D%8F%E8%AE%AE%E6%A0%88%E7%9A%84%E5%86%85%E9%83%A8%E7%BB%93%E6%9E%84"><span class="nav-text">2.1.1 协议栈的内部结构</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-1-2-%E5%A5%97%E6%8E%A5%E5%AD%97%E7%9A%84%E5%AE%9E%E4%BD%93%E5%B0%B1%E6%98%AF%E9%80%9A%E9%81%93%E6%8E%A7%E5%88%B6%E4%BF%A1%E6%81%AF"><span class="nav-text">2.1.2 套接字的实体就是通道控制信息</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-1-3-%E5%88%9B%E5%BB%BA%E5%A5%97%E6%8E%A5%E5%AD%97%E7%9A%84%E5%85%B7%E4%BD%93%E8%BF%87%E7%A8%8B"><span class="nav-text">2.1.3 创建套接字的具体过程</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-2-%E8%BF%9E%E6%8E%A5%E6%9C%8D%E5%8A%A1%E5%99%A8"><span class="nav-text">2.2 连接服务器</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#2-2-1-%E8%BF%9E%E6%8E%A5%E9%98%B6%E6%AE%B5%E5%81%9A%E7%9A%84%E4%BA%8B%E5%84%BF"><span class="nav-text">2.2.1 连接阶段做的事儿</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-2-2-%E8%B4%9F%E8%B4%A3%E4%BF%9D%E5%AD%98%E6%8E%A7%E5%88%B6%E4%BF%A1%E6%81%AF%E7%9A%84%E5%A4%B4%E9%83%A8"><span class="nav-text">2.2.2 负责保存控制信息的头部</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-2-3-%E8%BF%9E%E6%8E%A5%E6%93%8D%E4%BD%9C%E7%9A%84%E5%AE%9E%E9%99%85%E8%BF%87%E7%A8%8B"><span class="nav-text">2.2.3 连接操作的实际过程</span></a></li></ol></li></ol></li></ol></div>
        </div>
        <!--/noindex-->

        <div class="site-overview-wrap sidebar-panel">
          <div class="site-author animated" itemprop="author" itemscope itemtype="http://schema.org/Person">
  <p class="site-author-name" itemprop="name">鸣蜩十七</p>
  <div class="site-description" itemprop="description">记录我的学习、生活和恋爱日常</div>
</div>
<div class="site-state-wrap animated">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
        <a href="/archives/">
          <span class="site-state-item-count">43</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
          <a href="/categories/">
        <span class="site-state-item-count">8</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
          <a href="/tags/">
        <span class="site-state-item-count">37</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>

        </div>
      </div>
    </div>

    
  </aside>


    </div>

    <div class="main-inner post posts-expand">


  


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="http://xiaoqingming18.github.io/2023/07/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%EF%BC%9A%E7%BD%91%E7%BB%9C%E6%98%AF%E6%80%8E%E6%A0%B7%E8%BF%9E%E6%8E%A5%E7%9A%84/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="鸣蜩十七">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="鸣蜩十七">
      <meta itemprop="description" content="记录我的学习、生活和恋爱日常">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="计算机网络：网络是怎样连接的 | 鸣蜩十七">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          计算机网络：网络是怎样连接的
        </h1>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>

      <time title="创建时间：2023-07-12 09:07:23" itemprop="dateCreated datePublished" datetime="2023-07-12T09:07:23+08:00">2023-07-12</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar-check"></i>
      </span>
      <span class="post-meta-item-text">更新于</span>
      <time title="修改时间：2023-07-24 15:13:28" itemprop="dateModified" datetime="2023-07-24T15:13:28+08:00">2023-07-24</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">分类于</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/" itemprop="url" rel="index"><span itemprop="name">-计算机网络</span></a>
        </span>
    </span>

  
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">
        <h1 id="一、浏览器生成消息"><a href="#一、浏览器生成消息" class="headerlink" title="一、浏览器生成消息"></a>一、浏览器生成消息</h1><h2 id="1-1-生成HTTP请求消息"><a href="#1-1-生成HTTP请求消息" class="headerlink" title="1.1 生成HTTP请求消息"></a>1.1 生成HTTP请求消息</h2><h3 id="1-1-1-什么是URL"><a href="#1-1-1-什么是URL" class="headerlink" title="1.1.1 什么是URL"></a>1.1.1 什么是URL</h3><p>我们的网络体验从在浏览器中输入网址开始。网址，即URL，URL通过开头不同的标识区分不同的服务，例如访问Web服务器时使用”<a target="_blank" rel="noopener" href="http://&quot;，访问FTP服务器时使用&quot;ftp://&quot;。">http://"，访问FTP服务器时使用"ftp://"。</a></p>
<p>下图列举了几种常用的互联网URL：</p>
<p><img src="/2023/07/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%EF%BC%9A%E7%BD%91%E7%BB%9C%E6%98%AF%E6%80%8E%E6%A0%B7%E8%BF%9E%E6%8E%A5%E7%9A%84/常见的URL.png" alt="常见的URL"></p>
<p>URL的写法不同，但它们有一个共同点，就是URL开头的文字，即“http:”“ftp:”“file:”“mailto:”这部分文字都表示浏览器应 当使用的访问方法。比如当访问 Web 服务器时应该使用 HTTP协议，而 访问 FTP 服务器时则应该使用 FTP 协议。因此，我们可以把这部分理解为 访问时使用的协议类型。</p>
<h3 id="1-1-2-浏览器解析URL"><a href="#1-1-2-浏览器解析URL" class="headerlink" title="1.1.2 浏览器解析URL"></a>1.1.2 浏览器解析URL</h3><p>浏览器要先解析URL，才能生成发送给Web服务器的消息。下面我们以访问Web服务器为例介绍浏览器解析URL的过程：</p>
<ol>
<li>假设浏览器访问”<a target="_blank" rel="noopener" href="http://www.lovewujunli.com/love/day.html&quot;；">http://www.lovewujunli.com/love/day.html"；</a></li>
<li>浏览器首先对URL进行拆解，得到服务器名称（地址）、文件地址。</li>
<li>浏览器得到：要访问”www.lovewujunli.com”这个服务器上的”love”文件夹下的”dai.html”文件。</li>
</ol>
<h3 id="1-1-3-什么是HTTP协议"><a href="#1-1-3-什么是HTTP协议" class="headerlink" title="1.1.3 什么是HTTP协议"></a>1.1.3 什么是HTTP协议</h3><p>解析完URL之后，浏览器会使用HTTP协议来访问Web服务器，下面介绍一下什么是HTTP协议。</p>
<p><img src="/2023/07/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%EF%BC%9A%E7%BD%91%E7%BB%9C%E6%98%AF%E6%80%8E%E6%A0%B7%E8%BF%9E%E6%8E%A5%E7%9A%84/HTTP协议.png" alt="HTTP协议"></p>
<p>如上图，HTTP协议定义了客户端和服务器之间交互的消息内容和步骤。首先，客户端向服务器发送请求消息，请求消息包括方法和URI。其中，URI叫作统一资源标识符，简单来说URI标识了要访问的目标。方法表示要让Web服务器完成怎样的操作，下表列举了主要的方法：</p>
<p><img src="/2023/07/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%EF%BC%9A%E7%BD%91%E7%BB%9C%E6%98%AF%E6%80%8E%E6%A0%B7%E8%BF%9E%E6%8E%A5%E7%9A%84/HTTP的主要方法.png" alt="HTTP的主要方法"></p>
<p>客户端发送的请求消息除了请求方法和URI之外，还有一些用来表示附加信息的<strong>头字段</strong>。客户端向Web服务器发送数据时，会先发送头字段，然后再发送数据，后面会详细介绍头字。</p>
<p>收到请求消息之后，Web 服务器会对其中的内容进行解析，通过 URI 和方法来判断“对什么”“进行怎样的操作”，并根据这些要求来完成自己 的工作，然后将结果存放在响应消息中。在响应消息的开头有一个状态码， 它用来表示操作的执行结果是成功还是发生了错误。</p>
<p>响应消息会被发送回客户端，客户端收到之后，浏览器会从消息中读出所需的数据并显示在屏幕 上。到这里，HTTP 的整个工作就完成了。</p>
<h3 id="1-1-4-生成HTTP请求消息"><a href="#1-1-4-生成HTTP请求消息" class="headerlink" title="1.1.4 生成HTTP请求消息"></a>1.1.4 生成HTTP请求消息</h3><p>对URL进行解析之后浏览器知道要访问的服务器和内容了，接下来就浏览器就要按照规定的格式来生成请求消息了，请求消息的格式如下图所示：</p>
<p><img src="/2023/07/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%EF%BC%9A%E7%BD%91%E7%BB%9C%E6%98%AF%E6%80%8E%E6%A0%B7%E8%BF%9E%E6%8E%A5%E7%9A%84/HTTP消息的格式.png" alt="HTTP消息的格式"></p>
<p>首先，请求消息的第一行称为请求行。这里的重点是最开头的方法，方法可以告诉 Web 服务器它应该进行怎样的操作。浏览器通过提交请求的方式判断需要用什么方法，比如在地址栏输入URL回车之后浏览器就知道应该用GET方法，如果是在表单处发送请求，浏览器就知道应该用POST方法。</p>
<p>尽管通过第一行我们就可以大致理解请求的内容，但有些情况下还需要一些额外的详细信息，而消息头的功能就是用来存放这些信息。消息头的规格中定义了很多项目，如日期、客户端支持的数据类型、语言、压缩格式、客户端和服务器的软件名称和版本、数据有 效期和最后更新时间等。</p>
<h3 id="1-1-5-发送请求后收到响应"><a href="#1-1-5-发送请求后收到响应" class="headerlink" title="1.1.5 发送请求后收到响应"></a>1.1.5 发送请求后收到响应</h3><p>当浏览器向服务器发送请求后，会接受到服务器发送过来的响应消息，响应消息的格式在上面的图中已经给出了。下表向我们介绍了状态码大概的意思：</p>
<p><img src="/2023/07/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%EF%BC%9A%E7%BD%91%E7%BB%9C%E6%98%AF%E6%80%8E%E6%A0%B7%E8%BF%9E%E6%8E%A5%E7%9A%84/HTTP状态码概要.png" alt="HTTP状态码概要"></p>
<p>由于每条请求消息中只能写 1 个 URI，所以每次只能获取 1 个文件， 如果需要获取多个文件，必须对每个文件单独发送 1 条请求。比如 1 个网页中包含 3 张图片，那么获取网页加上获取图片，一共需要向 Web 服务器发送 4 条请求。</p>
<p>判断所需的文件，然后获取这些文件并显示在屏幕上，这一系列工作 的整体指挥是浏览器的任务之一，而 Web 服务器却毫不知情。Web 服务器完全不关心这 4 条请求获取的文件到底是 1 个网页上的还是不同网页上 的，它的任务就是对每一条单独的请求返回 1 条响应而已。</p>
<p>到这里，我们已经知道了了浏览器与 Web 服务器进行交互的整个过程。 《网络是怎样连接的》书中第一章最后展示了浏览器与 Web 服务器之间交互消息的一个实例，具体见该书第47页。</p>
<h2 id="1-2-向DNS服务器查询Web服务器的IP地址"><a href="#1-2-向DNS服务器查询Web服务器的IP地址" class="headerlink" title="1.2 向DNS服务器查询Web服务器的IP地址"></a>1.2 向DNS服务器查询Web服务器的IP地址</h2><h3 id="1-2-1-什么是IP地址"><a href="#1-2-1-什么是IP地址" class="headerlink" title="1.2.1 什么是IP地址"></a>1.2.1 什么是IP地址</h3><p>浏览器并不具备发送请求信息的功能，而是通过委托操作系统来发送请求消息，但在这之前要先通过解析URL得到的域名查询服务器的IP地址。在介绍这一操作之前，我们先了解一下什么是IP地址。</p>
<p>互联网和公司内部的局域网都是基于 TCP/IP 的思路来设计的，所以我们先来了解 TCP/IP 的基本思路。TCP/IP 的结构如图 1.8 所示，就是由一些 小的子网，通过路由器连接起来组成一个大的网络。这里的子网可以理解为用集线器连接起来的几台计算机，我们将它看作一个单位，称为子网。 将子网通过路由器连接起来，就形成了一个网络。</p>
<p><img src="/2023/07/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%EF%BC%9A%E7%BD%91%E7%BB%9C%E6%98%AF%E6%80%8E%E6%A0%B7%E8%BF%9E%E6%8E%A5%E7%9A%84/IP的基本思路.png" alt="IP的基本思路"></p>
<p>在网络中，所有的设备都会被分配一个地址。这个地址就相当于现实中某条路上的“×× 号 ×× 室”。其中“号”对应的号码是分配给整个子网的，而“室”对应的号码是分配给子网中的计算机的，这就是网络中的地址。“号”对应的号码称为网络号，“室”对应的号码称为主机号，这个地址的整体称为 IP 地址。</p>
<p>发送者发出的消息首先经过子网中的集线器，转发到距离发送者最近的路由器上（图 1.8 ①）。接下来，路由器会根据消息的目的地判断下一个路由器的位置，然后将消息发送到下一个路由器，即消息再次经过子网内的集线器被转发到下一个路由器（图 1.8 ②）。前面的过程不断重复，最终消息就被传送到了目的地。</p>
<p>前面这些就是 TCP/IP 中IP地址的基本思路。了解了这些知识之后，让我们再来看一下实际的 IP 地址。如图1.10所示，实际的IP地址是一串32比特的数字，按照8比特（1字节）为一组分成4组，分别用十进制表示然后再用圆点隔开。这就是我们平常经常见到的 IP 地址格式，但仅凭这一串数字我们无法区分哪部分是网络号，哪部分是主机号。在IP地址的规则 中，网络号和主机号连起来总共是32比特，但这两部分的具体结构是不固定的。在组建网络时，用户可以自行决定它们之间的分配关系，因此，我们还需要另外的附加信息来表示 IP 地址的内部结构。</p>
<p><img src="/2023/07/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%EF%BC%9A%E7%BD%91%E7%BB%9C%E6%98%AF%E6%80%8E%E6%A0%B7%E8%BF%9E%E6%8E%A5%E7%9A%84/IP地址的结构.png" alt="IP地址的结构"></p>
<p>这里的附加信息就是<strong>子网掩码</strong>，子网掩码是一 串与IP地址长度相同的32比特数字，其左边一半都是1，右边一半都是0。其中，子网掩码为1的部分表示网络号，子网掩码为0的部分表示主机号。第一种写法是将子网掩码按照和IP地址一样的方式以每8bit为单位用圆点分组后写在IP地址的右侧，如下图所示。</p>
<p><img src="/2023/07/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%EF%BC%9A%E7%BD%91%E7%BB%9C%E6%98%AF%E6%80%8E%E6%A0%B7%E8%BF%9E%E6%8E%A5%E7%9A%84/子网掩码第一种写法.png" alt="子网掩码第一种写法"></p>
<p>上面的写法太长，我们还可以把子网掩码中1的部分的位数用十进制表示，并写在IP地址的右侧，比如上图的例子，子网掩码中一共有24位二进制的1，就可以像下图一样简写子网掩码。</p>
<p><img src="/2023/07/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%EF%BC%9A%E7%BD%91%E7%BB%9C%E6%98%AF%E6%80%8E%E6%A0%B7%E8%BF%9E%E6%8E%A5%E7%9A%84/子网掩码简写法.png" alt="子网掩码简写法"></p>
<p>顺带一提，如下图所示，主机号有两种特别形式，即主机号部分全0或全1。</p>
<p><img src="/2023/07/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%EF%BC%9A%E7%BD%91%E7%BB%9C%E6%98%AF%E6%80%8E%E6%A0%B7%E8%BF%9E%E6%8E%A5%E7%9A%84/主机号特殊点.png" alt="主机号特殊点"></p>
<h3 id="1-2-2-Socket库提供查询IP地址的功能"><a href="#1-2-2-Socket库提供查询IP地址的功能" class="headerlink" title="1.2.2 Socket库提供查询IP地址的功能"></a>1.2.2 Socket库提供查询IP地址的功能</h3><p>查询 IP 地址的方法非常简单，只要询问最近的DNS服务器“www. lab.glasscom.com的IP地址是什么”就可以了，DNS服务器会回答说“该服务器的 IP 地址为 xxx.xxx.xxx.xxx”。这一过程很简单，那么浏览器是如何向DNS服务器发起查询的呢？让我们先来探索一下DNS。</p>
<p>对于DNS，用户的计算机上有相应的DNS客户端——<strong>DNS解析器</strong>，解析器实际上是一段程序，包含在操作系统的Socket库中，调用的是一个叫作 gethostbyname 的程序组件。Socket库可以让其他的应用程序调用操作系统的网络功能，解析器就是这个库中的一种程序组件。</p>
<p>下面我们来具体了解一下解析器。</p>
<h3 id="1-2-3-通过解析器向DNS服务器发出查询"><a href="#1-2-3-通过解析器向DNS服务器发出查询" class="headerlink" title="1.2.3 通过解析器向DNS服务器发出查询"></a>1.2.3 通过解析器向DNS服务器发出查询</h3><p>调用解析器后，解析器会向DNS服务器发送查询消息，然后DNS服务器会返回响应消息。响应消息中包含查询到的IP地址，解析器会取出IP地址，并将其写入浏览器指定的内存地址中。接 下来，浏览器在向Web服务器发送消息时，只要从该内存地址取出IP地址，并将它与HTTP请求消息一起交给操作系统就可以了。</p>
<h3 id="1-2-4-解析器的原理"><a href="#1-2-4-解析器的原理" class="headerlink" title="1.2.4 解析器的原理"></a>1.2.4 解析器的原理</h3><p> 网络应用程序（这里是浏览器）调用解析器时，程序的控制流程程就会转移到解析器的内部。随后解析器会生成一条要发送给DNS服务器的查询消息，DNS服务器会返回一条响应消息。解析器本身不能发送消息，而是要委托给操作系统内部的协议栈（操作系统内部的网络控制软件，也叫“协议驱动”“TCP/IP 驱动”等）发送查询消息。协议栈会执行发送消息的操作，然后通过网卡将消息发送给DNS服务器。DNS服务器接收到查询消息之后就会返回一条响应消息，包含域名对应的IP地址，这一整个过程称为<strong>域名解析</strong>。</p>
<h2 id="1-3-全世界DNS服务器的大接力"><a href="#1-3-全世界DNS服务器的大接力" class="headerlink" title="1.3 全世界DNS服务器的大接力"></a>1.3 全世界DNS服务器的大接力</h2><h3 id="1-3-1-DNS服务器的基本工作"><a href="#1-3-1-DNS服务器的基本工作" class="headerlink" title="1.3.1 DNS服务器的基本工作"></a>1.3.1 DNS服务器的基本工作</h3><p>来自客户端的查询消息包含下面三个信息：</p>
<ol>
<li>域名：服务器、邮件服务器（邮件地址中 @ 后面的部分）的名称。</li>
<li>Class：在最早设计 DNS 方案时，DNS 在互联网以外的其他网络中的应用也被考虑到了，而 Class 就是用来识别网络的信息。不过，如今除了 互联网并没有其他的网络了，因此 Class 的值永远是代表互联网的 IN。</li>
<li>记录类型：表示域名对应何种类型的记录。例如，当类型为 A 时，表示域名对应的是 IP 地址；当类型为 MX时，表示域名对应的是邮件服务器。对于不同的记录类型，服务器向客户端返回的信息也会不同。</li>
</ol>
<p><img src="/2023/07/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%EF%BC%9A%E7%BD%91%E7%BB%9C%E6%98%AF%E6%80%8E%E6%A0%B7%E8%BF%9E%E6%8E%A5%E7%9A%84/DNS服务器的基本工作.png" alt="DNS服务器的基本工作"></p>
<h3 id="1-3-2-域名的层次结构"><a href="#1-3-2-域名的层次结构" class="headerlink" title="1.3.2 域名的层次结构"></a>1.3.2 域名的层次结构</h3><p>DNS 服务器中的所有信息都是按照域名以分层次的结构来保存的。DNS中的域名都是用句点来分隔的，比如www.lab.glasscom.com，这里的句点代表了不同层次之间的界限，在域名中，越靠右的位置表示其层级越高。其中，相当于一个层级的部分称为<strong>域</strong>。例如前面的域名，com域的下一层是glasscom域，再下一层是lab域，再下面才是www这个名字。</p>
<p>于是，DNS服务器也具有了像域名一样的层次结构，每个域的信息都存放在相应层级的DNS服务器中。</p>
<p>再补充一点，在一个域下面可以创建<strong>下级域</strong>，比如，假设某公司的域为 example.cn，我们可以在这个域的下面创建两个子域,例如sub1. example.cn 和 sub2.example.cn，然后就可以将这两个下级域分配给公司不同的部门来使用。</p>
<h3 id="1-3-3-寻找相应的DNS服务器并获取IP地址"><a href="#1-3-3-寻找相应的DNS服务器并获取IP地址" class="headerlink" title="1.3.3 寻找相应的DNS服务器并获取IP地址"></a>1.3.3 寻找相应的DNS服务器并获取IP地址</h3><p>从DNS服务器获取域名对应的IP地址的关键是如何找到我们要访问的Web服务器信息归哪一台DNS服务器管。</p>
<p>首先，将负责管理下级域的DNS服务器的IP地址注册到它们的上级DNS服务器中，然后上级 DNS 服务器的IP地址再注册到更上一级的 DNS 服务器中，以此类推。这样，我们就可以通过上级DNS服务器查询出下级DNS服务器的IP地址，也就可以向下级 DNS 服务器发送查询请求了。</p>
<p>在互联网中，com和cn的上面还有一级域，称为根域，书写域名时常被省略。根域的DNS服务器中保管着com、cn等的 DNS 服务器的信息。根域的DNS服务器信息保存在互联网中所有的DNS服务器中。这样一来，任何DNS服务器就都可以找到并访问根域DNS服务器了。因此，客户端只要能够找到任意一台DNS服务器，就可以通过它找到根域DNS服务器，然后再一路顺藤摸瓜找到位于下层的某台目标 DNS 服务器。这个过程如下图所示。</p>
<p><img src="/2023/07/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%EF%BC%9A%E7%BD%91%E7%BB%9C%E6%98%AF%E6%80%8E%E6%A0%B7%E8%BF%9E%E6%8E%A5%E7%9A%84/寻找DNS服务器过程.png" alt="寻找DNS服务器的过程"></p>
<h3 id="1-3-4-通过缓存加快DNS服务器的响应"><a href="#1-3-4-通过缓存加快DNS服务器的响应" class="headerlink" title="1.3.4 通过缓存加快DNS服务器的响应"></a>1.3.4 通过缓存加快DNS服务器的响应</h3><p>有时候并不需要从最上级的根域开始查找，因为 DNS 服务器有一 个缓存功能，可以记住之前查询过的域名。如果要查询的域名和相关信息已经在缓存中，那么就可以直接返回响应，接下来的查询可以从缓存的位置开始向下进行。相比每次都从根域找起来说，缓存可以减少查询所需的时间。</p>
<p>并且，当要查询的域名不存在时，“不存在”这一响应结果也会被缓存。这样，当下次查询这个不存在的域名时，也可以快速响应。</p>
<p>这个缓存机制中有一点需要注意，那就是信息被缓存后，原本的注册信息可能会发生改变，这时缓存中的信息就有可能是不正确的。因此，DNS服务器中保存的信息都设置有一个有效期，当缓存中的信息超过有效期后，数据就会从缓存中删除。</p>
<h2 id="1-4-委托协议栈发送消息"><a href="#1-4-委托协议栈发送消息" class="headerlink" title="1.4 委托协议栈发送消息"></a>1.4 委托协议栈发送消息</h2><h3 id="1-4-1-数据收发操作概览"><a href="#1-4-1-数据收发操作概览" class="headerlink" title="1.4.1 数据收发操作概览"></a>1.4.1 数据收发操作概览</h3><p>知道了 IP 地址之后，就可以委托操作系统内部的协议栈向这个目标 IP 地址，也就是我们要访问的 Web 服务器发送消息了。这里需要按照指定的顺序调用多个程序组件，这个过程有点复杂，下图简要概述这个过程。</p>
<p><img src="/2023/07/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%EF%BC%9A%E7%BD%91%E7%BB%9C%E6%98%AF%E6%80%8E%E6%A0%B7%E8%BF%9E%E6%8E%A5%E7%9A%84/数据收发过程.png" alt="数据收发过程"></p>
<p>进行收发数据操作之前，双方需要先建立起收发数据的管道才行。建立管道的关键在于管道两端的数据出入口，这些出入口称为<strong>套接字</strong>。</p>
<p>首先，服务器一方先创建套接字，然后等待客户端向该套接字连接管道 。当服务器进入等待状态时，客户端就可以连接管道了。具体来说，客户端也会先创建一个套接字，当双方的套接字连接起来之后，通信准备就完成了。接下来，就像我们刚刚讲过的一样，只要将数据送入套接字就可以收发数据了。</p>
<p>当数据全部发送完毕之后，连接的管道将会被断开。管道在连接时是由客户端发起的，但在断开时可以由客户端或服务器任意一方发起。其中一方断开后，另一方也会随之断开，当管道断开后，套接字也会被删除。到此为止，通信操作就结束了。</p>
<p>综上所述，收发数据的操作分为若干个阶段，可以大致总结为以下 4 个：</p>
<ol>
<li>创建套接字（创建套接字阶段） 。</li>
<li>将管道连接到服务器端的套接字上（连接阶段） 。</li>
<li>收发数据（通信阶段） 。</li>
<li>断开管道并删除套接字（断开阶段）</li>
</ol>
<p>这4个操作都是由操作系统中的协议栈来执行的，浏览器等应用程序并不会自己去做连接管道、放入数据这些工作，而是委托协议栈来代劳。</p>
<p>下面分阶段来介绍一下收发数据的具体过程。</p>
<h3 id="1-4-2-创建套接字阶段"><a href="#1-4-2-创建套接字阶段" class="headerlink" title="1.4.2 创建套接字阶段"></a>1.4.2 创建套接字阶段</h3><p>应用程序（浏览器）委托收发数据过程的关键点就是像对 DNS 服务器发送查询一样，调用 Socket 库中的socket 程序组件。</p>
<p>套接字创建完成后，协议栈会返回一个描述符，应用程序会将收到的描述符存放在内存中。描述符是用来识别计算机内协议栈中不同的套接字的，不是用来识别另一方的套接字。比如浏览器打开多个网页，就会在客户端协议栈内创建多个套接字，这里的描述符就是用来识别客户端协议栈内多个套接字的。只要我们出示描述符， 协议栈就能够判断出我们希望用哪一个套接字来连接或者收发数据了。</p>
<h3 id="1-4-3-连接阶段"><a href="#1-4-3-连接阶段" class="headerlink" title="1.4.3 连接阶段"></a>1.4.3 连接阶段</h3><p>接下来，我们需要委托协议栈将客户端创建的套接字与服务器那边的套接字连接起来。应用程序通过调用Socket库中的connect的程序组件来完成这一操作。当调用 connect 时，需要指定描述符、 服务器 IP 地址和端口号这 3 个参数，下面介绍一下这三个参数的作用。</p>
<ol>
<li><strong>描述符</strong>：就是在创建套接字的时候由协议栈返回的那 个描述符。connect 会将应用程序指定的描述符告知协议栈，然后协议栈根据这个描述符来判断到底使用哪一个套接字去和服务器端的套接字进行连接，并执行连接的操作。</li>
<li><strong>服务器 IP 地址</strong>，就是通过 DNS 服务器查询得到的我们要访问的服务器的 IP 地址。在 DNS 服务器的部分已经讲过，在进行数据收发操作时，双方必须知道对方的 IP 地址并告知协议栈。</li>
<li><strong>端口号</strong>：描述符是用来在一台机器中选择协议栈某一个套接字进行连接操作的，端口号则是用来在服务器中识别具体的套接字的，IP地址用来连接到某个服务器，端口号则是具体选择对应服务器的某个套接字。服务器上所使用的端口号是根据应用的种类事先规定好的，比如 Web 是 80 号端口，电子邮件是 25 号端口。</li>
</ol>
<p><img src="/2023/07/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%EF%BC%9A%E7%BD%91%E7%BB%9C%E6%98%AF%E6%80%8E%E6%A0%B7%E8%BF%9E%E6%8E%A5%E7%9A%84/描述符与端口号的区别.png" alt="描述符与端口号的区别"></p>
<p>当连接成功后，协议栈会将对方的 IP 地址和端口号等信息保存在套接字中，这样我们就可以开始收发数据了。</p>
<h3 id="1-4-4-通信阶段：传递消息"><a href="#1-4-4-通信阶段：传递消息" class="headerlink" title="1.4.4 通信阶段：传递消息"></a>1.4.4 通信阶段：传递消息</h3><p>当套接字连接起来之后，剩下的事情就简单了。只要将数据送入套接字，数据就会被发送到对方的套接字中。这个操作需 要使用Socket库中write这个程序组件，具体过程如下。</p>
<p>首先，应用程序需要在内存中准备好要发送的数据。根据用户输入的网址生成的 HTTP 请求消息就是我们要发送的数据。接下来，当调用 write 时，需要指定描述符和发送数据，然后协议栈就会将数据发送到服务器。由于在完成上一个连接阶段之后，套接字中已经保存了已连接的通信对象的相关信息（包括端口号），所以只要通过描述符指定套接字，就可以识别出通信对象，并向其发送数据。 接着，发送数据会通过网络到达我们要访问的服务器。</p>
<p>接下来，服务器执行接收操作，解析收到的数据内容并执行相应的操作，向客户端返回响应消息。</p>
<p>当消息返回后，需要执行的是接收消息的操作。接收消息的操作是通过 Socket 库中的 read 程序组件委托协议栈来完成的。调用 read 时需要指定用于存放接收到的响应消息的内存地址，这一内存地址称为<strong>接收缓冲区</strong>。接收缓冲区是一块位于应用程序内部的内存空间，因此当消息被存放到接收缓冲区中时，就相当于已经转交给了应用程序。</p>
<h3 id="1-4-5-断开阶段：收发数据结束"><a href="#1-4-5-断开阶段：收发数据结束" class="headerlink" title="1.4.5 断开阶段：收发数据结束"></a>1.4.5 断开阶段：收发数据结束</h3><p>当浏览器收到数据之后，收发数据的过程就结束了。接下来，我们需要调用 Socket 库的 close 程序组件进入断开阶段，之后协议栈内对应的套接字会被删除，数据通路（前面说的管道）也随之消失。</p>
<p>断开的过程如下。Web 使用的 HTTP 协议规定，当 Web 服务器发送完响应消息之后，应该主动执行断开操作 ，因此 Web 服务器会首先调用 close 来断开连接。断开操作传达到客户端之后，客户端的套接字也会进入 断开阶段。接下来，当浏览器调用 read 执行接收数据操作时，read 会告知浏览器收发数据操作已结束，连接已经断开。浏览器得知后，也会调用close 进入断开阶段。</p>
<p>要注意的是，根据应用种类不同，客户端和服务器哪一方先执行close都有可能。有些应用中是客户端先执行close。</p>
<p>这就是 HTTP 的工作过程。HTTP 协议将 HTML 文档和图片都作为单独的对象来处理，每获取一次数据，就要执行一次连接、发送请求消息、 接收响应消息、断开的过程。因此，如果一个网页中包含很多张图片，就必须重复进行很多次连接、收发数据、断开的操作。</p>
<h2 id="第一章结语"><a href="#第一章结语" class="headerlink" title="第一章结语"></a>第一章结语</h2><p>到这里第一章就结束了，本章了解了浏览器与 Web 服务器之间收发消息的过程，但实际负责收发消息的是协议栈、网卡驱动和网卡，只有这 3 者相互配合，数据才能够在网络中流动起来。下一章将对这一部分进行探索。</p>
<h1 id="二、协议栈和网卡"><a href="#二、协议栈和网卡" class="headerlink" title="二、协议栈和网卡"></a>二、协议栈和网卡</h1><h2 id="2-1-创建套接字"><a href="#2-1-创建套接字" class="headerlink" title="2.1 创建套接字"></a>2.1 创建套接字</h2><h3 id="2-1-1-协议栈的内部结构"><a href="#2-1-1-协议栈的内部结构" class="headerlink" title="2.1.1 协议栈的内部结构"></a>2.1.1 协议栈的内部结构</h3><p>协议栈的结构如下所示，分为不同部分，并且执行流是从上到下的：</p>
<p><img src="/2023/07/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%EF%BC%9A%E7%BD%91%E7%BB%9C%E6%98%AF%E6%80%8E%E6%A0%B7%E8%BF%9E%E6%8E%A5%E7%9A%84/协议栈的结构.png" alt="协议栈的结构"></p>
<p>最上面的部分是网络应用程序，也就是浏览器、电子邮件客户端、Web 服务器、电子邮件服务器等程序，它们会将收发数据等工作委派给下层的部分来完成。</p>
<p>应用程序的下面是 Socket 库，其中包括解析器，解析器用来向 DNS 服务器发出查询。再下面就是操作系统内部了，其中包括协议栈。协议栈的上半部分有两块，分别是负责用 TCP 协议收发数据的部分和负责用 UDP 协议收发数据的部分。</p>
<blockquote>
<p>浏览器、邮件等一般应用程序收发数据时用 TCP； </p>
<p>DNS 查询等收发较短的控制数据时用 UDP。</p>
</blockquote>
<p>下面一半是用 IP 协议控制网络包收发操作的部分。在互联网上传送数据时，数据会被切分成一个一个的网络包 ，而将网络包发送给通信对象的工作就是由IP模块完成的。IP 中还包括 ICMPA 协议和 ARPB 协议。 ICMP 用于告知网络包传送过程中产生的错误以及各种控制消息，ARP 用于根据 IP 地址查询相应的以太网 MAC 地址。</p>
<p> IP 下面的网卡驱动程序负责控制网卡硬件，而最下面的网卡则负责完成实际的收发操作，也就是对网线中的信号执行发送和接收的操作</p>
<h3 id="2-1-2-套接字的实体就是通道控制信息"><a href="#2-1-2-套接字的实体就是通道控制信息" class="headerlink" title="2.1.2 套接字的实体就是通道控制信息"></a>2.1.2 套接字的实体就是通道控制信息</h3><p>在协议栈内部有一块用于存放控制信息的内存空间，这里记录了用于控制通信操作的控制信息，例如通信对象的 IP 地址、端口号、通信操作的进行状态等。<strong>套接字的实体就是协议栈内部存放通道控制信息</strong>。</p>
<p>协议栈在执行操作时需要参阅这些控制信息。例如，在发送数据时，需要看一看套接字中的通信对象 IP 地址和端口号，在发送数据时套接字中还必须要记录是否已经收到响应，以及发送数据后经过了多长时间，根据这些信息在可以在数据发送失败后重新发送。</p>
<p>综上所述，协议栈是根据套接字中记录的控制信息来工作的。</p>
<h3 id="2-1-3-创建套接字的具体过程"><a href="#2-1-3-创建套接字的具体过程" class="headerlink" title="2.1.3 创建套接字的具体过程"></a>2.1.3 创建套接字的具体过程</h3><p>应用程序调用 socket 申请创建套接字，协议栈首先会分配用于存放一个套接字所需的内存空间，用于记录套接字控制信息。套接字刚刚创建时，数据收发操作还没有开始，因此需要在套接字的内存空间中写入表示这一初始状态的控制信息。到这里，创建套接字的操作就完成了。</p>
<p>简单来说，创建套接字时，首先分配一个套接字所需的内存空间，然后向其中写入初始状态。</p>
<h2 id="2-2-连接服务器"><a href="#2-2-连接服务器" class="headerlink" title="2.2 连接服务器"></a>2.2 连接服务器</h2><h3 id="2-2-1-连接阶段做的事儿"><a href="#2-2-1-连接阶段做的事儿" class="headerlink" title="2.2.1 连接阶段做的事儿"></a>2.2.1 连接阶段做的事儿</h3><p>这里的连接并不是我们所认为的网络的连接，因为网络通过网线一直都是处于连接状态的，这里的<strong>连接实际上是通信双方交换控制信息</strong>，在套接字中记录这些必要信息并准备数据收发的一连串操作。</p>
<p>套接字刚创建完成时里面没有任何数据，所以它不知道通信的对象是谁，所以协议栈也不知道要给谁发送数据。但浏览器可以通过解析URL查询到服务器的IP地址，同时也可以知道要使用的端口号。<strong>连接的第一步操作便是浏览器将通信对象的具体信息通过套接字告诉协议栈</strong>。</p>
<p>服务器上的套接字情况是一样的，也不知道通信对象的具体信息。和客户端不一样，服务器的应用程序也不知道通信对象（即客户端）的具体信息。于是<strong>连接的另一个目的就是让客户端告诉服务器关于客户端的具体信息</strong>，包括客户端IP地址与端口号等。</p>
<p>上面提到的<strong>控制信息就是在收发数据时所需的一些信息</strong>，比如IP地址和端口号，除此之外还有一些其他的控制信息。连接操作中交换的控制信息是根据通信规则来确定的，也就是说使用不同的通信规则所需的控制信息也不同。</p>
<p>此外，在执行数据收发操作时，我们需要一块用来临时存放要收发的数据的内存空间，这块内存空间称为缓冲区，这也是在连接的阶段进行的。</p>
<p>综上，我们可以总结一下连接阶段具体做了哪些事儿：</p>
<ol>
<li>浏览器将通信对象的信息放入套接字。</li>
<li>告诉服务器关于客户端的信息。</li>
<li>在客户端开辟<strong>缓冲区</strong>，用来临时存放要收发的数据。</li>
</ol>
<h3 id="2-2-2-负责保存控制信息的头部"><a href="#2-2-2-负责保存控制信息的头部" class="headerlink" title="2.2.2 负责保存控制信息的头部"></a>2.2.2 负责保存控制信息的头部</h3><p>我们上面说的控制信息可以分为两类：一类是客户端和服务器相互联络时交换的控制信息，另一类是保存在套接字中用来控制协议栈操作数据的控制信息。</p>
<p>我们先来看看客户端和服务器相互联络时交换的控制信息，<strong>这些信息在整个通信阶段都需要</strong>。这些信息位于网络包的开头，所以又称为<strong>头部</strong>。此外，以太网和 IP 协议也有自己的控制信息，这些信息也叫头部，为了避免各种不同的头部发生混淆，我们一般会记作<strong>TCP头部</strong>、<strong>以太网头部</strong> 、<strong>IP</strong>头部。</p>
<p>客户端和服务器在通信中会将必要的信息记录在头部并相互确认，例如下面这样：</p>
<blockquote>
<p>发送方：“开始数据发送。” </p>
<p>接收方：“请继续。” </p>
<p>发送方：“现在发送的是 ×× 号数据。” </p>
<p>接收方：“×× 号数据已收到。” </p>
<p>……（以下省略）</p>
</blockquote>
<p>我们上面所说的是<strong>TCP协议</strong>，下面我们来看看它的具体格式：</p>
<p><img src="/2023/07/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%EF%BC%9A%E7%BD%91%E7%BB%9C%E6%98%AF%E6%80%8E%E6%A0%B7%E8%BF%9E%E6%8E%A5%E7%9A%84/TCP头部格式.png" alt="TCP头部格式"></p>
<p>下面我们再来看看保存在套接字中用来控制协议栈操作数据的控制信息，这些信息保存在协议栈中的套接字内存空间中。应用程序传过来的数据以及从通信对象接收到的数据都会保存在这里。套接字的控制信息和协议栈的程序本身其实是一体的，即协议栈中的控制信息通信对方是看不见的，但只要在通信时按照规则将必要的信息写入头部，客户端和服务器之间的通信就能够得以成立。</p>
<p><img src="/2023/07/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%EF%BC%9A%E7%BD%91%E7%BB%9C%E6%98%AF%E6%80%8E%E6%A0%B7%E8%BF%9E%E6%8E%A5%E7%9A%84/客户端与服务器之间交换的控制信息.png" alt="客户端与服务器之间交换的控制信息"></p>
<p><img src="/2023/07/12/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C%EF%BC%9A%E7%BD%91%E7%BB%9C%E6%98%AF%E6%80%8E%E6%A0%B7%E8%BF%9E%E6%8E%A5%E7%9A%84/控制信息分类.png" alt="控制信息分类"></p>
<h3 id="2-2-3-连接操作的实际过程"><a href="#2-2-3-连接操作的实际过程" class="headerlink" title="2.2.3 连接操作的实际过程"></a>2.2.3 连接操作的实际过程</h3><p>我们已经知道，连接是从应用程序调用 Socket 库的 connect 开始的，这个调用会将服务器的IP地址传递给协议栈中的TCP模块。然后TCP模块会与该IP地址对应的通信对象的TCP模块交换控制信息，下面我们探讨一下交互的具体流程。</p>
<p>首先，客户端创建一个包含表示开始进行数据收发操作的控制信息的头部，从表2.1的TCP头部格式我们可以知道，头部里包含发送方和接收方的端口号，到这里客户端（发送方）就找到了服务器（接收方）的套接字</p>
<p>然后，将头部中的控制位的 SYN 比特设置为 1，现在可以认为它表示连接，后面会详细讲解。此外还需要设置适当的序号和窗口大小，这一点也会在后面详细讲解。</p>
<p>上面两段我们可以知道，连接操作的第一步是在 TCP 模块处创建表示连接控制信息的头部。然后通过 TCP 头部中的发送方和接收方端口号可以找到要连接的套接字。</p>
<p>TCP头部创建好之后，TCP模块会将信息传递给IP模块委托它来发送，IP模块会将网络包通过网络发送给服务器。然后服务器上的IP模块会将接收到的数据传递给TCP模块，然后服务器的 TCP 模块根据 TCP 头部中的信息找到端口号对应的套接字。当找到对应的套接字之后，套接字中会写入相应的信息，并将状态改为正在连接。</p>
<p>上述操作完成后，服务器的 TCP 模块会返回响应，这个过程和客户端一样，需要在 TCP 头部中设置发送方和接收方端口号以及 SYN 比特。如果由于某些原因不接受连接，那么将不设置 SYN，而是将 RST 比特设 置为 1。</p>
<p>在返回响应时还需要将 ACK 控制位设为 1，这表示已经接收到相应的网络包。网络中经常会发生错误，网络包也会发生丢失，因此双方在通信时必须相互确认网络包是否已经送达 ，而设置 ACK 比特就是用来进行这一确认的。接下来，服务器 TCP 模块会将 TCP 头部传递给 IP 模块，并委托 IP 模块向客户端返回响应。</p>
<p>然后，网络包就会返回到客户端，通过 IP 模块到达 TCP 模块，并通过 TCP 头部的信息确认连接服务器的操作是否成功。如果 SYN 为 1 则表示连接成功，这时会向套接字中写入服务器的 IP 地址、端口号等信息，同时还会将状态改为连接完毕，最后客户端也需要将 ACK 比特设置为 1 并发回服务器，告诉服务器刚才的响应包已经收到。当这个服务器收到这个返回包之后，连接操作才算全部完成。</p>
<p>现在，套接字就已经进入随时可以收发数据的状态了。</p>

    </div>

    
    
    

    <footer class="post-footer">
          <div class="post-tags">
              <a href="/tags/%E7%BD%91%E7%BB%9C%E6%98%AF%E6%80%8E%E6%A0%B7%E8%BF%9E%E6%8E%A5%E7%9A%84-%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/" rel="tag"># -网络是怎样连接的 -读书笔记</a>
          </div>

        

          <div class="post-nav">
            <div class="post-nav-item">
                <a href="/2023/07/10/%E5%8F%98%E9%87%8F%E3%80%81%E4%BD%9C%E7%94%A8%E5%9F%9F%E5%92%8C%E5%86%85%E5%AD%98/" rel="prev" title="">
                  <i class="fa fa-chevron-left"></i> 
                </a>
            </div>
            <div class="post-nav-item">
                <a href="/2023/07/14/JavaScript%EF%BC%9A%E5%87%BD%E6%95%B0/" rel="next" title="JavaScript：函数">
                  JavaScript：函数 <i class="fa fa-chevron-right"></i>
                </a>
            </div>
          </div>
    </footer>
  </article>
</div>






</div>
  </main>

  <footer class="footer">
    <div class="footer-inner">


<div class="copyright">
  &copy; 
  <span itemprop="copyrightYear">2023</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">鸣蜩十七</span>
</div>
  <div class="powered-by">由 <a href="https://hexo.io/" rel="noopener" target="_blank">Hexo</a> & <a href="https://theme-next.js.org/muse/" rel="noopener" target="_blank">NexT.Muse</a> 强力驱动
  </div>

    </div>
  </footer>

  
  <div class="toggle sidebar-toggle" role="button">
    <span class="toggle-line"></span>
    <span class="toggle-line"></span>
    <span class="toggle-line"></span>
  </div>
  <div class="sidebar-dimmer"></div>
  <div class="back-to-top" role="button" aria-label="返回顶部">
    <i class="fa fa-arrow-up fa-lg"></i>
    <span>0%</span>
  </div>

<noscript>
  <div class="noscript-warning">Theme NexT works best with JavaScript enabled</div>
</noscript>


  
  <script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js" integrity="sha256-XL2inqUJaslATFnHdJOi9GfQ60on8Wx1C2H8DYiN1xY=" crossorigin="anonymous"></script>
<script src="/js/comments.js"></script><script src="/js/utils.js"></script><script src="/js/motion.js"></script><script src="/js/schemes/muse.js"></script><script src="/js/next-boot.js"></script>

  




  




  

  <script class="next-config" data-name="enableMath" type="application/json">true</script><script class="next-config" data-name="mathjax" type="application/json">{"enable":true,"tags":"none","js":{"url":"https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.2.2/es5/tex-mml-chtml.js","integrity":"sha256-MASABpB4tYktI2Oitl4t+78w/lyA+D7b/s9GEP0JOGI="}}</script>
<script src="/js/third-party/math/mathjax.js"></script>



</body>
</html>
